// 给定一位研究者论文被引用次数的数组（被引用次数是非负整数）。编写一个方法，计算出研究者的 h 指数。

// h 指数的定义：h 代表“高引用次数”（high citations），一名科研人员的 h 指数是指他（她）的 （N 篇论文中）总共有 h 篇论文分别被引用了至少 h 次。（其余的 N - h 篇论文每篇被引用次数 不超过 h 次。）

// 例如：某人的 h 指数是 20，这表示他已发表的论文中，每篇被引用了至少 20 次的论文总共有 20 篇。

//  

// 示例：

// 输入：citations = [3,0,6,1,5]
// 输出：3 
// 解释：给定数组表示研究者总共有 5 篇论文，每篇论文相应的被引用了 3, 0, 6, 1, 5 次。
//      由于研究者有 3 篇论文每篇 至少 被引用了 3 次，其余两篇论文每篇被引用 不多于 3 次，所以她的 h 指数是 3。
//  

// 提示：如果 h 有多种可能的值，h 指数是其中最大的那个。

#include <vector>

using namespace std;

/* 排序
从小到大排序，然后从高到低遍历，n-i是当前论文的数量，citations[i]是引用次数
if (citations[i] < n - i) return n - i - 1;
时间复杂度：O(NlogN)
空间复杂度：O(1)
*/
class Solution {
public:
    int hIndex(vector<int>& citations) {
        if (citations.empty()) return 0;
        sort(citations.begin(), citations.end()); // 升序排序
        int n = citations.size();
        for (int i{n-1}; i >= 0; --i) {
            if (citations[i] < n - i) return n - i - 1;
        }
        return n;
    }
};

/* 排序
时间复杂度：O(NlogN)
空间复杂度：O(1)
*/
class Solution {
public:
    int hIndex(vector<int>& citations) {
        sort(citations.begin(), citations.end()); // 升序排序
        int res{0};
        int n = citations.size();
        while (res < n && citations[n - res - 1] > res) {
            ++res;
        }
        return res;
    }
};

/* 计数排序
论文的引用次数可能会非常多，这个数值很可能会超过论文的总数 n，因此使用计数排序是非常不合算的（会超出空间限制）。
重要发现：如果一篇文章的引用次数超过论文的总数 n，那么将它的引用次数降低为 n 也不会改变 h 指数的值。
时间复杂度：O(N)
空间复杂度：O(N)
*/
class Solution {
public:
    int hIndex(vector<int>& citations) {
        int n = citations.size();
        vector<int> papers(n + 1, 0);
        // 计数
        for (int c : citations) {
            ++papers[min(n, c)]; // c比n大的话就取n
        }
        // 找出最大的k
        int res = n;
        for (int s = papers[n]; res > s; s += papers[res]) {
            --res;
        }
        return res;
    }
};